#
# Copyright (c) 2025 Huawei Technologies Co., Ltd.
# openUBMC is licensed under Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
#         http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
# See the Mulan PSL v2 for more details.
#

"""
嵌套函数代码分析工具
"""

from mcpy.ir.base import IRNode
from mcpy.ir.statements.control import (
    IRContinue,
    IRIf,
    IRForRange,
    IRForEach,
    IRWhile,
    IRBreak,
)
from mcpy.ir.statements.assignment import IRAssign
from mcpy.ir.statements.control import IRIf
from mcpy.ir.expressions.await_expr import IRAwait
from mcpy.ir.expressions.basic import IRName


def has_undeclared_local_vars(
    stmt: IRNode, state_vars: dict, func_scope_local_vars: set
) -> bool:
    """递归检查语句中是否有未声明的局部变量

    Args:
        stmt: 语句节点
        state_vars: 成员变量字典
        func_scope_local_vars: 函数头局部变量集合

    Returns:
        如果有未声明的局部变量返回 True
    """

    if isinstance(stmt, IRAssign):
        # 跳过 await 赋值
        if isinstance(stmt.value, IRAwait):
            return False

        target = stmt.get_target_expr()
        if target and isinstance(target, IRName):
            var_name = target.id
            # 不是成员变量且不在函数头，就是未声明的
            if var_name not in state_vars and var_name not in func_scope_local_vars:
                return True

    elif isinstance(stmt, IRIf):
        # 递归检查 if 分支
        if stmt.then_body:
            for s in stmt.then_body.statements:
                if has_undeclared_local_vars(s, state_vars, func_scope_local_vars):
                    return True

        if stmt.else_body:
            for s in stmt.else_body.statements:
                if has_undeclared_local_vars(s, state_vars, func_scope_local_vars):
                    return True

    return False


def collect_local_var_definitions(
    stmt: IRNode, local_vars: set, state_vars: dict
) -> None:
    """递归收集局部变量定义（不包括成员变量）

    Args:
        stmt: 语句节点
        local_vars: 输出参数，收集的局部变量集合
        state_vars: 成员变量字典
    """
    if isinstance(stmt, IRAssign):
        # 跳过 await 赋值（结果变量在其他地方处理）
        if isinstance(stmt.value, IRAwait):
            return

        target = stmt.get_target_expr()
        if target and isinstance(target, IRName):
            var_name = target.id
            # 不是成员变量的才是局部变量
            if var_name not in state_vars:
                local_vars.add(var_name)

    elif isinstance(stmt, IRIf):
        # 递归处理 if 分支
        if stmt.then_body:
            for s in stmt.then_body.statements:
                collect_local_var_definitions(s, local_vars, state_vars)

        if stmt.else_body:
            for s in stmt.else_body.statements:
                collect_local_var_definitions(s, local_vars, state_vars)

    elif isinstance(stmt, (IRForRange, IRForEach, IRWhile)):
        # 递归处理其他控制流
        if stmt.body:
            for s in stmt.body.statements:
                collect_local_var_definitions(s, local_vars, state_vars)


def has_break_in_statements(statements: list, stop_at_loop: bool = True) -> bool:
    """检测语句列表中是否包含 break 语句

    Args:
        statements: 语句列表
        stop_at_loop: 是否在遇到循环时停止递归（避免检测嵌套循环的 break）

    Returns:
        是否包含 break 语句
    """

    for stmt in statements:
        if isinstance(stmt, IRBreak):
            return True
        elif isinstance(stmt, IRIf):
            # 递归检查 if 分支
            if stmt.then_body and has_break_in_statements(
                stmt.then_body.statements, stop_at_loop
            ):
                return True
            if stmt.else_body and has_break_in_statements(
                stmt.else_body.statements, stop_at_loop
            ):
                return True
        elif isinstance(stmt, (IRForRange, IRForEach, IRWhile)):
            # 如果遇到嵌套循环，根据 stop_at_loop 决定是否继续
            if not stop_at_loop and stmt.body:
                if has_break_in_statements(stmt.body.statements, stop_at_loop):
                    return True
    return False


def has_continue_in_statements(statements: list, stop_at_loop: bool = True) -> bool:
    """检测语句列表中是否包含 continue 语句

    Args:
        statements: 语句列表
        stop_at_loop: 是否在遇到循环时停止递归（避免检测嵌套循环的 continue）

    Returns:
        是否包含 continue 语句
    """

    for stmt in statements:
        if isinstance(stmt, IRContinue):
            return True
        elif isinstance(stmt, IRIf):
            # 递归检查 if 分支
            if stmt.then_body and has_continue_in_statements(
                stmt.then_body.statements, stop_at_loop
            ):
                return True
            if stmt.else_body and has_continue_in_statements(
                stmt.else_body.statements, stop_at_loop
            ):
                return True
        elif isinstance(stmt, (IRForRange, IRForEach, IRWhile)):
            # 如果遇到嵌套循环，根据 stop_at_loop 决定是否继续
            if not stop_at_loop and stmt.body:
                if has_continue_in_statements(stmt.body.statements, stop_at_loop):
                    return True
    return False
